home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 68161 / 68161.xpi / chrome / content / twitkitplus.js < prev    next >
Text File  |  2010-02-10  |  58KB  |  1,617 lines

  1. /*
  2.     TwitKit+ v0.0.1
  3.     
  4.     Based off of Tweetbar by Mike Demers [mike@mikedemers.net]
  5.     
  6.     homepage:  http://engel.uk.to/twitkitplus
  7. */
  8.  
  9. /**
  10.  * The main JavaScript class for TwitKit+.
  11.  * 
  12.  * @class
  13.  * @requires MooTools
  14.  * @version 1.2.2
  15.  */
  16. var Tweetbar = {
  17.     
  18.     // Variables //
  19.     /**
  20.      * Tweets for each panel are stored here
  21.      */
  22.     tweets: {
  23.         friends: {},
  24.         followers: {},
  25.         public_timeline: {},
  26.         home_timeline: {},
  27.         replies: {},
  28.         direct_messages: {},
  29.         me: {},
  30.     },
  31.     /**
  32.      * Used for parsing Twitter's created_at API property later on
  33.      */
  34.     month_names: ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'],
  35.     /**
  36.      * User is(n't) authenticated
  37.      */
  38.     isAuthenticated: false,
  39.     /**
  40.      * The current list being viewed
  41.      */
  42.     currentList: null,
  43.     /**
  44.      * Stores the updater object created by MooTools periodical() function
  45.      */
  46.     updater: null,
  47.     /**
  48.      * The MooTools Fx object responsible for showing/hiding the login window
  49.      */
  50.     loginSlider: null,
  51.     /**
  52.      * The current user's Twitter username
  53.      */
  54.     username: null,
  55.     /**
  56.      * The current user's Twitter password
  57.      */
  58.     password: null,
  59.     /**
  60.      * If we're waiting for the user to log in to do something, the action that
  61.      * will be performed is stored here.
  62.      */
  63.     pendingAction: null,
  64.     /**
  65.      * Cached HTTP headers to send with API requests
  66.      */
  67.     httpHeaders: null,
  68.     /**
  69.      * The service responsible for retrieving and setting preferences
  70.      */
  71.     prefService: null,
  72.     /**
  73.      * Service which reads/writes cookies
  74.      */
  75.     cookieService: null,
  76.     /**
  77.      * Service that retrieves localized strings
  78.      */
  79.     stringBundleService: null,
  80.     /**
  81.      * Shorthand way of accessing Tweetbar.stringBundleService
  82.      */
  83.     strings: null,
  84.     
  85.     // Startup Functions //
  86.     /**
  87.      * Initializes TwitKit+ processes and prepares the
  88.      * sidebar. This function is essential for TwitKit+ to
  89.      * function correctly.
  90.      * 
  91.      * @constructor
  92.      * @methodOf Tweetbar
  93.      * @since 1.0
  94.      */
  95.     run:
  96.         function () {
  97.             Tweetbar.prefService = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("extensions.twitkitplus.");
  98.             Tweetbar.cookieService = Components.classes["@mozilla.org/cookiemanager;1"].getService(Components.interfaces.nsICookieManager);
  99.             
  100.             // l10n //
  101.             Tweetbar.stringBundleService = Components.classes["@mozilla.org/intl/stringbundle;1"].getService(Components.interfaces.nsIStringBundleService);
  102.             Tweetbar.strings = {
  103.                 UI: Tweetbar.stringBundleService.createBundle('chrome://twitkitplus/locale/ui.properties')
  104.             };
  105.             this.localize();
  106.  
  107.             // Markdown //
  108.             Tweetbar.markDown = new Showdown.converter();
  109.             
  110.             // Docking //
  111.             var url = window.location.href;
  112.             if ( url.search('undocked') !== -1 ) {
  113.                 $('is-undocked').remove();
  114.             }
  115.             
  116.             Tweetbar.DOMWindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
  117.                 .getInterface(Components.interfaces.nsIWebNavigation)
  118.                 .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
  119.                 .rootTreeItem
  120.                 .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
  121.                 .getInterface(Components.interfaces.nsIDOMWindow);
  122.             
  123.             var scheme = Tweetbar.prefService.getCharPref('colorScheme').toLowerCase();
  124.             var link = new Element('link');
  125.             link.setProperties({
  126.                 'rel': 'stylesheet',
  127.                 'href': 'chrome://twitkitplus/skin/themes/' + scheme + '.css',
  128.                 'type': 'text/css',
  129.                 'media': 'screen',
  130.             });
  131.             link.injectInside('thehead');
  132.             $('thebody').setStyle('font-size', Tweetbar.prefService.getCharPref('fontSize') + '%');
  133.             
  134.             this.setListSize();
  135.             
  136.             this.loginSlider = new Fx.Slide('loginform', {duration: 500});
  137.             this.loginSlider.hide();
  138.  
  139.             ( Tweetbar.prefService.getBoolPref('secureConnection') ) ? Tweetbar.protocol = 'https' : Tweetbar.protocol = 'http';
  140.             
  141.             if ( Tweetbar.protocol == 'https' ){
  142.                 $('using-ssl').setProperty('src', 'chrome://twitkitplus/skin/images/ssl-on.png');
  143.             }else{
  144.                 $('using-ssl').setProperty('src', 'chrome://twitkitplus/skin/images/ssl-off.png');
  145.             }
  146.             var initial_panel = Tweetbar.prefService.getCharPref('active_panel');
  147.             if ( initial_panel == '' ){
  148.                 initial_panel = 'public_timeline';
  149.             }
  150.             
  151.             try {
  152.                 Tweetbar.username = Tweetbar.prefService.getCharPref('username');
  153.                 Tweetbar.password = Tweetbar.prefService.getCharPref('password');
  154.                 if ( Tweetbar.username !== '' && Tweetbar.password !== '' ) {
  155.                     Tweetbar.isAuthenticated = true;
  156.                     Tweetbar.set_username_on_page();
  157.                 } else {
  158.                     Tweetbar.username = null;
  159.                     Tweetbar.password = null;
  160.                 }
  161.             } catch (e) { }
  162.             
  163.             this.activate_panel(initial_panel);
  164.         },
  165.     /**
  166.      * Translates all words in the HTML document to the
  167.      * user's current locale.
  168.      * 
  169.      * @methodOf Tweetbar
  170.      * @since 1.1
  171.      */
  172.     localize:
  173.         function () {
  174.             $('.signin').innerHTML = this._('login.signIn');
  175.             $('login-header').innerHTML = this._('login.header');
  176.             $('username-label').innerHTML = this._('login.form.username');
  177.             $('password-label').innerHTML = this._('login.form.password');
  178.             $('loginbutton').setProperty('value', this._('login.form.submit'));
  179.             $('signup').innerHTML = this._('login.signUp', '<a href="' + Tweetbar.protocol + '://twitter.com/account/create?tb_10" target="_content">', '</a>');
  180.             $('question').innerHTML = this._('poster.question');
  181.             $('compress').setProperty('title', this._('poster.compress'));
  182.             $('public').innerHTML = this._('tabs.public.title');
  183.             $('user').innerHTML = this._('tabs.user.title');
  184.             $('friends').innerHTML = this._('tabs.friends.title');
  185.             $('followers').innerHTML = this._('tabs.followers.title');
  186.             $('replies').innerHTML = this._('tabs.replies.title');
  187.             $('direct-messages').innerHTML = this._('tabs.directMessages.title');
  188.             $('me').innerHTML = this._('tabs.me.title');
  189.             $('refreshing').innerHTML = this._('misc.refreshing');
  190.             $('refresh').innerHTML = this._('misc.refresh');
  191.             $('clear-link').innerHTML = this._('misc.clear');
  192.             $('loading').innerHTML = this._('misc.loading');
  193.         },
  194.     
  195.     // l10n //
  196.     /**
  197.      * Translates a string into the user's current locale.
  198.      * If one parameter is given, the string is retrieved.
  199.      * If more than one parameters are given, the string is
  200.      * formatted with the 2nd, 3rd, 4th parameters, etc.
  201.      * 
  202.      * @param {String} label Word to localize
  203.      * @param {String} [vars=""] (optional) Extra variables
  204.      * @returns {String} A localized string
  205.      * @methodOf Tweetbar
  206.      * @since 1.1
  207.      */
  208.     _:
  209.         function (label) {
  210.             if ( arguments.length === 1 ) {
  211.                 try {
  212.                     return Tweetbar.strings.UI.GetStringFromName(label);
  213.                 } catch (e) {
  214.                     return label;
  215.                 }
  216.             }
  217.             return Tweetbar.strings.UI.formatStringFromName(label,
  218.                 Array.prototype.slice.call(arguments, 1),
  219.                 arguments.length - 1);
  220.         },
  221.     
  222.     // HTTP Headers //
  223.     /**
  224.      * Reset all HTTP headers (used in logging in/out)
  225.      * 
  226.      * @methodOf Tweetbar
  227.      * @since 1.0
  228.      */
  229.     clear_http_headers:
  230.         function () {
  231.             Tweetbar.httpHeaders = null;
  232.         },
  233.     /**
  234.      * Return standarad HTTP headers to be sent to Twitter.
  235.      * 
  236.      * @returns {Array} An array of HTTP headers.
  237.      * @methodOf Tweetbar
  238.      * @since 1.0
  239.      */
  240.     http_headers:
  241.         function () {
  242.             if ( !Tweetbar.httpHeaders ) {
  243.                 Tweetbar.httpHeaders = {
  244.                     'X-Twitter-Client': 'TwitKit',
  245.                     'X-Twitter-Client-Version': '0.0.1',
  246.                     'X-Twitter-Client-URL': 'http://engel.uk.to/twitkit/1.2.2.xml',
  247.                 };
  248.                 if ( Tweetbar.username && Tweetbar.password )
  249.                     Tweetbar.httpHeaders['Authorization'] = Tweetbar.http_basic_auth();
  250.             }
  251.             return Tweetbar.httpHeaders;
  252.         },
  253.     /**
  254.      * Return Basic authentication for HTTP headers.
  255.      * 
  256.      * @returns {String} Basic authentication string.
  257.      * @methodOf Tweetbar
  258.      * @since 1.0
  259.      */
  260.     http_basic_auth:
  261.         function () {
  262.             return 'Basic ' + btoa(Tweetbar.username + ':' + Tweetbar.password);
  263.         },
  264.     
  265.     // Cookies //
  266.     /**
  267.      * Clears cookies for twitter.com, to prevent sign-in
  268.      * problems.
  269.      * 
  270.      * @methodOf Tweetbar
  271.      * @since 1.0
  272.      */
  273.     clear_cookies:
  274.         function () {
  275.             var url = 'HTTP://TWITTER.COM';
  276.             var iter = Tweetbar.cookieService.enumerator;
  277.             while ( iter.hasMoreElements() ) {
  278.                 var cookie = iter.getNext();
  279.                 if ( cookie instanceof Components.interfaces.nsICookie ) {
  280.                     if ( url.indexOf(cookie.host.toUpperCase()) != -1 )
  281.                         Tweetbar.cookieService.remove(cookie.host, cookie.name, cookie.path, cookie.blocked);
  282.                 }
  283.             }
  284.         },
  285.     
  286.     // Miscellaneous //
  287.     /**
  288.      * Returns the Twitter API request URL for the specified action.
  289.      * 
  290.      * @param {String} resource A valid Twitter API request.
  291.      * @methodOf Tweetbar
  292.      * @since 1.0
  293.      */
  294.     api_url_for_statuses:
  295.         function (resource,param) {
  296.             if(param != undefined ){
  297.                 addparam = param;
  298.             }else{
  299.                 addparam = '';
  300.             }
  301.             return Tweetbar.protocol + '://twitter.com/statuses/' + resource + '.json' + addparam;
  302.         },
  303.     api_url_for_nonstatuses:
  304.         function (resource,param) {
  305.             return Tweetbar.protocol + '://twitter.com/' + resource + '.json'+ addparam;
  306.         },
  307.     api2_url_for_statuses:
  308.         function (resource,param) {
  309.             return Tweetbar.protocol + '://api.twitter.com/1/statuses/' + resource + '.json'+ addparam;
  310.         },
  311.  
  312. //    api_url_for_more_statuses:
  313. //        function (resource) {
  314. //            return Tweetbar.protocol + '://twitter.com/statuses/home_timeline.json?max_id=' + resource;
  315. //        },
  316.     /**
  317.      * Make links and replies clickable.
  318.      * 
  319.      * @param {String} s Tweet text
  320.      * @returns {String} Tweet text with clickable links and Twitter names
  321.      * @methodOf Tweetbar
  322.      * @since 1.0
  323.      */
  324.     expand_status:
  325.         function (s) {
  326.             ret = s.toString();
  327.             ret = ret.replace(/\</,'<');
  328.             //twitpic
  329.             reg_twitpic = new RegExp('http:\/\/(www\.|)twitpic\.com\/([a-zA-Z0-9]+)([?()!).,\\s]|<|$)', 'g');
  330.             ret = ret.replace(reg_twitpic, '<a rel="twitpic_gm" href="tkavoidurl://twitpic.com/$2" target="_blank"><img style="border: 1px solid #ccc; float: left; margin: 0 3px 3px 0; height: 72px; width: 72px;" src="tkavoidurl://twitpic.com/show/thumb/$2" border="0" /></a>$3');
  331.             //movepic
  332.             reg_movapic = new RegExp('http:\/\/movapic\.com\/pic\/([a-zA-Z0-9]+)([?()!).,\\s]|<|$)', 'g');
  333.             ret = ret.replace(reg_movapic, '<a rel="twitpic_gm" href="tkavoidurl://movapic.com/pic/$1" target="_blank"><img style="border: 1px solid #ccc; float: left; margin: 0 3px 3px 0; height: 72px; width: 72px;" src="tkavoidurl://image.movapic.com/pic/s_$1.jpeg" border="0" /></a>$2');
  334.             //make <a> tag
  335.             re = new RegExp('(<\\w+.*?>|[^=!:\'"/]|^|)((?:https?:\/\/)|(?:irc:\/\/)|(?:www\.){4})([-\\w]+(?:\.[-\\w]+)*(?::\\d+)?(?:/(?:(?:[~\\w\\+#%-]|(?:[,.;@:][^\\s$]))+)?)*(?:\\?[\\w\\+%&=.;:-]+)?(?:\#[\\w\-\.]*)?)([?()!).,\\s]|<|$)', 'gi');
  336.             ret = ret.replace(re, '$1' + this.anchor_tag('$2$3') + '$4');
  337.             //ëµæ£ùpURLé≡î│é╔û▀é╖
  338.             re = new RegExp('tkavoidurl://', 'g');
  339.             ret = ret.replace(re, 'http://');
  340.             ret = ret.replace(/<a href="www/g, '<a href="http:\/\/www');
  341.             ret = ret.replace(/<a href="(\S+) ([^<>]+)" target(.+)>(\S+) ([^<]+)<\/a>/, '<a href="$1" target$3>$1</a> $5');
  342.             ret = ret.replace(/([\w-]+)@([\w-]+\.)([\w-]+)/, this.anchor_tag('mailto:$1@$2$3', '$1@$2$3'));
  343.             ret = ret.replace(/(\s|^)\@([0-9a-z_A-Z]+)/g, this.anchor_tag(Tweetbar.protocol + ':\/\/twitter.com/$2'.toLowerCase(),'$1@$2','$2 ' + this._('misc.onTwitter')));
  344.             return ret;
  345.         },
  346.     /**
  347.      * Take a JSON object, parse it for parameters we need, and format them.
  348.      *
  349.      * @param {Object} obj A JSON object returned from the Twitter API.
  350.      * @returns {Object} A filtered and formatted tweet object
  351.      * @methodOf Tweetbar
  352.      * @since 1.0
  353.      */
  354.     create_status_object:
  355.         function (obj) {
  356.             return {
  357.                 'id': parseInt(obj.id),
  358.                 'text': Tweetbar.expand_status(obj.text),
  359.                 'created_at': Date.parse(obj.created_at || Date()),
  360.                 'source': obj.source,
  361.                 'favorited': obj.favorited,
  362.                 'truncated': obj.truncated,
  363.                 'reply_id': parseInt(obj.in_reply_to_status_id)
  364.             }
  365.         },
  366.     /**
  367.      * Take a JSON object containing a user, parse it, and format it.
  368.      * 
  369.      * @param {Object} obj A JSON object returned from a 'friends' or 'followers' API request.
  370.      * @returns {Object} A filtered and formatted user object
  371.      * @see Tweetbar#create_status_object
  372.      * @methodOf Tweetbar
  373.      * @since 1.0
  374.      */
  375.     create_user_object:
  376.         function (obj) {
  377.             return {
  378.                 'id': parseInt(obj.id),
  379.                 'url': obj.url,
  380.                 'profile_image_url': obj.profile_image_url,
  381.                 'name': obj.name,
  382.                 'location': obj.location,
  383.                 'description': obj.description,
  384.                 'screen_name': obj.screen_name,
  385.             }
  386.         },
  387.     /**
  388.      * Link a username to its Twitter profile.
  389.      * 
  390.      * @param {String} user A user object returned from Tweetbar#create_user_object.
  391.      * @param {String} [text="$username"] The text to show in the link. Username by default.
  392.      * @returns {String} A linked tag.
  393.      * @see Tweetbar#create_user_object
  394.      * @see Tweetbar#anchor_tag
  395.      * @methodOf Tweetbar
  396.      * @since 1.0
  397.      */
  398.     user_anchor_tag:
  399.         function (user, text) {
  400.             var name;
  401.             ( Tweetbar.prefService.getCharPref('showNamesAs') == 'screennames' ) ? name = user['screen_name'] : name = user['name'];
  402.             return this.anchor_tag(Tweetbar.protocol + '://twitter.com/' + user['screen_name'],
  403.                 ( (text) ? text : name),
  404.                 user['name'] + ' in ' + user['location']);
  405.         },
  406.     /**
  407.      * Anchor a tag.
  408.      * 
  409.      * @param {String} url The URL to link to.
  410.      * @param {String} [text=""] The text to anchor.
  411.      * @param {String} [title=""] Title to use (text displayed when link is hovered over).
  412.      * @returns {String} An anchored tag.
  413.      * @methodOf Tweetbar
  414.      * @since 1.0
  415.      */
  416.     anchor_tag:
  417.         function (url, text, title) {
  418.             return '<a href="'+url+'" target="_blank" title="' +
  419.                 ( (title) ? title : '') +'" alt="'+
  420.                 ( (title) ? title : '') +'">'+
  421.                 ( (text) ? text : url ) + '</a>';
  422.         },
  423.     /**
  424.      * Convert a date returned from Twitter API requests to a relative time string.
  425.      * 
  426.      * @param {String} time_value A date returned from Twitter API requests
  427.      * @returns {String} Relative time string
  428.      * @methodOf Tweetbar
  429.      * @since 1.0
  430.      */
  431.     relative_time_string:
  432.         function (time_value) {
  433.             var delta = parseInt(((new Date).getTime() - time_value) / 1000);
  434.            
  435.             if ( delta < 60 )
  436.                 return 'less than a minute ago';
  437.             else if ( delta < 120 )
  438.                 return 'about a minute ago';
  439.             else if ( delta < ( 45*60 ) )
  440.                 return ( parseInt(delta / 60) ).toString() + ' minutes ago';
  441.             else if ( delta < ( 90*60 ) )
  442.                 return 'about an hour ago';
  443.             else if ( delta < ( 24*60*60 ) )
  444.                 return 'about ' + ( parseInt(delta / 3600) ).toString() + ' hours ago';
  445.             else if ( delta < ( 48*60*60 ) )
  446.                 return '1 day ago';
  447.             else
  448.                 return ( parseInt(delta / 86400) ).toString() + ' days ago';
  449.         },
  450.     
  451.     // Misc. Tweet Functions //
  452.     /**
  453.      * This is a shorthand method of retrieving the tweets currently being displayed.
  454.      * 
  455.      * @returns {Object} An object filled with tweets
  456.      * @methodOf Tweetbar
  457.      * @since 1.0
  458.      */
  459.     current_tweets:
  460.         function () {
  461.             return this.tweets[this.currentList];
  462.         },
  463.     /**
  464.      * Clear tweets from the current panel.
  465.      * 
  466.      * @methodOf Tweetbar
  467.      * @since 1.0
  468.      */
  469.     clear_current_tweets:
  470.         function () {
  471.             var panel = this.currentList;
  472.             
  473.             for ( var tweet in this.tweets[panel] ) {
  474.                 if ( this.tweets[panel][tweet]._b )
  475.                     delete this.tweets[panel][tweet];
  476.             }
  477.             this.update_current_list();
  478.         },
  479.     
  480.  
  481.     // URL Compression //
  482.     /**
  483.      * Replaces a long URL in the status box with a URL compressed by is.gd
  484.      * 
  485.      * @methodOf Tweetbar
  486.      * @since 1.0
  487.      */
  488.     compress_url:
  489.         function () {
  490.             var originalinput = document.getElementById('status').value;
  491.             var originurl = document.getElementById('status').value.match(/(https?|ftp)(:\/\/[-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]+)/g);  //'
  492.             var shortener_service = Tweetbar.prefService.getCharPref('shortenerService').toLowerCase();
  493.             if ( originurl.length == 0 ){
  494.                 return;
  495.             }
  496.             for(var i=0;i<originurl.length;i++){
  497.                 var convert_results = '';
  498.                 var raw_data_results ;
  499.                 var temp_originurl = originurl[i];
  500.  
  501.                 if(originurl[i].length > 25){
  502.                     if ( shortener_service == 'is.gd' ) {
  503.                         var shortener_url = "http://is.gd/api.php?longurl=";
  504.                         var url = shortener_url+escape(originurl[i]);
  505.                         var aj = new Ajax( url, {
  506.                             method: 'get',
  507.                             postBody: {},
  508.                             onSuccess:
  509.                                 function (replaced) {
  510.                                     convert_results = replaced;
  511.                                     originalinput = originalinput.replace(temp_originurl,convert_results);
  512.                                     document.getElementById('status').value = originalinput;
  513.                                     $('nav-label').setHTML('finish URL shoten'+i);
  514.                                     updateStatusTextCharCounter(originalinput);
  515.                                 }
  516.                         }).request();
  517.                     } else if ( shortener_service == 'bit.ly' ) {
  518.                         var shortener_url = "http://api.bit.ly/shorten?version=2.0.1&longUrl=";
  519.                         var extra_bits = "&login=timeserver&apiKey=R_667934812dd1de4236f8eadad88d7846";
  520.                         var url = shortener_url+escape(originurl[i])+extra_bits;
  521.                         var aj = new Ajax( url, {
  522.                             method: 'get',
  523.                             postBody: {},
  524.                             onSuccess:
  525.                                 function (raw_data) {
  526.                                     raw_data_results = raw_data;//different process only bit.ly
  527.                                     convert_results = Json.evaluate(raw_data_results).results[temp_originurl].shortUrl
  528.                                     originalinput = originalinput.replace(temp_originurl,convert_results);
  529.                                     document.getElementById('status').value = originalinput;
  530.                                     $('nav-label').setHTML('finish URL shoten'+i);
  531.                                     updateStatusTextCharCounter(originalinput);
  532.                 }
  533.                         }).request();
  534.                     } else if ( shortener_service == 'tinyurl' ) {
  535.                         var shortener_url = "http://tinyurl.com/api-create.php?url=";
  536.                         var url = shortener_url+escape(originurl[i]);
  537.                         var aj = new Ajax( url, {
  538.                             method: 'get',
  539.                             postBody: {},
  540.                             onSuccess:
  541.                                 function (replaced) {
  542.                                     convert_results = replaced;
  543.                                     originalinput = originalinput.replace(temp_originurl,convert_results);
  544.                                     document.getElementById('status').value = originalinput;
  545.                                     $('nav-label').setHTML('finish URL shoten'+i);
  546.                                     updateStatusTextCharCounter(originalinput);
  547.                                 }
  548.                         }).request();
  549.                     } else if ( shortener_service == 'tr.im' ) {
  550.                         var shortener_url = "http://tr.im/api/trim_simple?url=";
  551.                         var url = shortener_url+escape(originurl[i]);
  552.                         var aj = new Ajax( url, {
  553.                             method: 'get',
  554.                             postBody: {},
  555.                             onSuccess:
  556.                                 function (replaced) {
  557.                                     convert_results = replaced;
  558.                                     originalinput = originalinput.replace(temp_originurl,convert_results);
  559.                                     document.getElementById('status').value = originalinput;
  560.                                     $('nav-label').setHTML('finish URL shoten'+i);
  561.                                     updateStatusTextCharCounter(originalinput);
  562.                                 }
  563.                         }).request();
  564.                     } else if ( shortener_service == 'xrl.us' ) {
  565.                         var shortener_url = "http://metamark.net/api/rest/simple?long_url=";
  566.                         var url = shortener_url+escape(originurl[i]);
  567.                         var aj = new Ajax( url, {
  568.                             method: 'get',
  569.                             postBody: {},
  570.                             onSuccess:
  571.                                 function (replaced) {
  572.                                     convert_results = replaced;
  573.                                     originalinput = originalinput.replace(temp_originurl,convert_results);
  574.                                     document.getElementById('status').value = originalinput;
  575.                                     $('nav-label').setHTML('finish URL shoten'+i);
  576.                                     updateStatusTextCharCounter(originalinput);
  577.                                 }
  578.                         }).request();
  579.                     }
  580.                 }
  581.             }
  582.         },
  583.         
  584.     // Rendering //
  585.     /**
  586.      * Render a tweet (but don't print it).
  587.      * 
  588.      * @param {Object} tweet A tweet object returned by Tweetbar#create_status_object.
  589.      * @param {Object} li A MooTools Element object of a 'li' element.
  590.      * @returns {String} Fully-rendered tweet HTML.
  591.      * @see Tweetbar#create_status_object
  592.      * @methodOf Tweetbar
  593.      * @since 1.0
  594.      */
  595.     render_tweet:
  596.         function (tweet, li) {
  597.             var display_date = '';
  598.             if ( tweet ) {
  599.                 if ( !tweet._a ){
  600.                     tweet._a = true;
  601.                 }else if ( !tweet._b ){
  602.                     tweet._b = true;
  603.                 }
  604.                 if ( this.currentList != 'replies' && this.currentList != 'me'){
  605.                     li.setProperty('id', tweet.id);
  606.                 }
  607.                 
  608.                 var user_image = '';
  609.                 if ( tweet.user && tweet.user.profile_image_url ){
  610.                     user_image = '<img src="' + tweet.user.profile_image_url + '" width="24" height="24" alt="' + tweet.user.name + '" />';
  611.                 }
  612.  
  613.                 ( tweet.user.screen_name == Tweetbar.username ) ? dellink = '<a href="#" onclick="Tweetbar.delete_tweet(\'' + tweet.id + '\');"><img style="border: none; float: right;" src="chrome://twitkitplus/skin/images/delete.png" alt="" /></a>' : dellink = '';
  614.                 
  615.                 ( this.currentList == 'replies' ) ? date = '' : date = ' - ' + Tweetbar.relative_time_string(tweet.created_at);
  616.                 
  617.                 /*
  618.                  * Hashtags implementation - by Joschi
  619.                  */
  620. //                tweet.text = tweet.text.replace(/(\s|^|)(#(\w*))([\s.!()/]|$)/g,'$1<a target="_blank" href="http://hashtags.org/tag/$3">$2</a>$4');
  621.                 tweet.text = tweet.text.replace(/(\s|^|)(#(\w*))([\s.!()/]|$)/g,'$1<a target="_blank" href="http://search.twitter.com/search?q=%23$3">$2</a>$4');
  622.                 // Markdown //
  623.                 tweet.text = Tweetbar.markDown.makeHtml(tweet.text);
  624.                 favorite = '';
  625.                 if ( tweet.favorited == true )
  626.                     favorite = '<a class="re" href="javascript: Tweetbar.unfav_tweet(\'' + tweet.id + '\'); void 0;" onmouseover="$(\'nav-label\').innerHTML = \'del favorite\';" onmouseout="$(\'nav-label\').innerHTML = \' \';"><img id="fav-' + tweet.id + '" class="re" src="chrome://twitkitplus/skin/images/fav_remove.png" alt="" /></a>';
  627.                 else
  628.                     favorite = '<a class="re" href="javascript: Tweetbar.fav_tweet(\'' + tweet.id + '\'); void 0;" onmouseover="$(\'nav-label\').innerHTML = \'add favorite\';" onmouseout="$(\'nav-label\').innerHTML = \' \';"><img id="fav-' + tweet.id + '" class="re" src="chrome://twitkitplus/skin/images/fav_add.png" alt="" /></a>';
  629.                 
  630.                 if ( tweet.truncated )
  631.                     tweet.text = tweet.text.replace(/\.\.\.$/, Tweetbar.anchor_tag(Tweetbar.protocol + '://twitter.com/' + tweet.user.screen_name + '/statuses/' + tweet.id, '...'));
  632.                 
  633.                 if ( tweet.in_reply_to_status_id ) {
  634.                     user_regexp = /@([a-zA-Z0-9_]+)/;
  635.                     user = user_regexp.exec(tweet.text)[1];
  636.                     in_reply_to = '<br> in reply to <a href="' + Tweetbar.protocol + '://twitter.com/' + user + '/statuses/' + tweet.in_reply_to_status_id + '/" target="_blank">' + tweet.in_reply_to_status_id + '</a>';
  637.                 } else if( tweet.reply_id ){
  638.                     user_regexp = /@([a-zA-Z0-9_]+)/;
  639.                     user = user_regexp.exec(tweet.text)[1];
  640.                     in_reply_to = '<br> in reply to <a href="' + Tweetbar.protocol + '://twitter.com/' + user + '/statuses/' + tweet.reply_id + '/" target="_blank">' + tweet.reply_id + '</a>';
  641.                 } else {
  642.                     in_reply_to = '';
  643.                 }
  644.                 //icons
  645.                 link_reply = '<a class="re" href="#" onclick="setReply(\''+ tweet.user.screen_name + '\',\'' + tweet.id + '\'); return false;" onmouseover="$(\'nav-label\').innerHTML = \'reply\';" onmouseout="$(\'nav-label\').innerHTML = \' \';"><img class="re" src="chrome://twitkitplus/skin/images/reply.png" alt="" /></a>';
  646.  
  647.                 link_reply_with_pic = '<a href="#" onclick="setReply(\'' + tweet.user.screen_name + '\',\'' + tweet.id +'\');">'+ user_image + '</a>';
  648.                 var img_match = '';
  649.                 img_match = tweet.text.match(/<img .*?>/);
  650.                 if(img_match != undefined && img_match.length != null){
  651.                     img_match = img_match.toSource().match(/(https?|ftp):\/\/[-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]+/); //'
  652.                     link_qt_text = tweet.text.replace(/<.*?>/g, "") + " " + img_match[0];
  653.                 }else{
  654.                     link_qt_text = tweet.text.replace(/<.*?>/g, "");
  655.                 }
  656.  
  657.                 link_qt = '<a class="re" href="#" onclick="setQT(\''+ tweet.user.screen_name + '\',decodeURI(\'' + encodeURI(link_qt_text) + '\'),\'' + tweet.id + '\'); return false;" onmouseover="$(\'nav-label\').innerHTML = \'QuoteTweet\';" onmouseout="$(\'nav-label\').innerHTML = \' \';"><img class="re" src="chrome://twitkitplus/skin/images/qt.png" alt="" /></a>';
  658.  
  659.                 link_rt = '<a class="re" href="#" onclick="if(confirm(\'Twitkit\+ : \\n want to retweet?\')){Tweetbar.send_retweet(\'retweet\',' + tweet.id + ');} return false;"><img class="re" src="chrome://twitkitplus/skin/images/rt.png" onmouseover="$(\'nav-label\').innerHTML = \'Public ReTweet\';" onmouseout="$(\'nav-label\').innerHTML = \' \';" alt="" /></a>';
  660.  
  661.  
  662.                 link_follow = '<a class="re" href="javascript: Tweetbar.follow_user(\'' + tweet.user.screen_name + '\'); void 0;" onmouseover="$(\'nav-label\').innerHTML = \'follow\';" onmouseout="$(\'nav-label\').innerHTML = \' \';"><img class="re" src="chrome://twitkitplus/skin/images/follow.png" /></a>';
  663.  
  664.                 link_unfollow = '<a class="re" href="javascript: Tweetbar.unfollow_user(\'' + tweet.user.screen_name + '\'); void 0;" onmouseover="$(\'nav-label\').innerHTML = \'unfollow\';" onmouseout="$(\'nav-label\').innerHTML = \' \';"><img class="re" src="chrome://twitkitplus/skin/images/unfollow.png" alt="" /></a>';
  665.  
  666.                 link_userinfo = '<a href="#" onclick="Tweetbar.activate_panel(\'me\',this,\'' + tweet.user.screen_name + '\'); void 0;" onmouseover="$(\'nav-label\').innerHTML = Tweetbar._(\'tabs.me.title\');" onmouseout="$(\'nav-label\').innerHTML = \' \';"><img class="re" src="chrome://twitkitplus/skin/tabs/me.png" width=10 height=10 /></a>';
  667.  
  668.  
  669.                 link_debug = '';
  670.                 //link_debug = '<a class="re" href="#" onclick = "var hohoge = \'' + escape(tweet.toSource().replace(/,/g, "\n").replace(/\\/g, "%")) + '\'; alert(unescape((unescape(hohoge))));" onmouseover="$(\'nav-label\').innerHTML = \'debug.info.decoded\';" onmouseout="$(\'nav-label\').innerHTML = \' \';"><img class="re" src="chrome://twitkitplus/skin/images/debug.png" alt="" /></a> <a class="re" href="#" onclick = "var hohoge = \'' + escape(tweet.toSource().replace(/,/g, "\n")) + '\'; alert(unescape((unescape(hohoge))));" onmouseover="$(\'nav-label\').innerHTML = \'debug.info\';" onmouseout="$(\'nav-label\').innerHTML = \' \';"><img class="re" src="chrome://twitkitplus/skin/images/debug.png" alt="" /></a>';
  671.  
  672.                 var tsource = tweet.source.replace(/<a /, '<a target="_blank" ');
  673.                 link_icon = link_reply + ' ' + link_qt + ' ' + link_rt + ' ' +  favorite + ' ' + link_userinfo + ' ' + link_follow + ' ' + link_unfollow ;
  674.                 
  675.                 ( Tweetbar.prefService.getBoolPref('showAppSource') ) ? source = '<div class="source">' + link_icon + ' ' + this._('misc.from') + ' ' + tsource +  ' '  +  '</div>' : source = '<div class="source">' + link_icon +  '</div>';
  676.                 return '<p class="pic">' + link_reply_with_pic + link_debug + '</p>' +
  677.                        '<p class="what">' + tweet.text + '</p>' +
  678.                        '<p class="who">' + this.user_anchor_tag(tweet.user) + date + in_reply_to + '</p>' +
  679.                        source + dellink;
  680.             }
  681.         },
  682.     /**
  683.      * Render a direct message (but don't print it).
  684.      * 
  685.      * @param {Object} tweet A tweet object returned by Tweetbar#create_status_object.
  686.      * @param {Object} li A MooTools Element object of a 'li' element.
  687.      * @returns {String} Fully-rendered tweet HTML.
  688.      * @see Tweetbar#create_status_object
  689.      * @methodOf Tweetbar
  690.      * @since 1.2
  691.      */
  692.     render_direct_message:
  693.         function (tweet, li) {
  694.             var display_date = '';
  695.             if ( tweet ) {
  696.                 if ( !tweet._a )
  697.                     tweet._a = true;
  698.                 else if ( !tweet._b )
  699.                     tweet._b = true;
  700.                 if ( this.currentList != 'direct_messages' )
  701.                     li.setProperty('id', tweet.id);
  702.                 
  703.                 var sender_image = '';
  704.                 if ( tweet.sender && tweet.sender.profile_image_url )
  705.                     sender_image = '<img src="' + tweet.sender.profile_image_url + '" width="24" height="24" alt="' + tweet.sender.name + '" />';
  706.                 
  707.                 ( this.currentList == 'direct_messages' ) ? date = '' : date = ' - ' + Tweetbar.relative_time_string(tweet.created_at);
  708.                 
  709.                 /*
  710.                  * Hashtags implementation - by Joschi
  711.                  */
  712.                 tweet.text = tweet.text.replace(/(\s|^|)(#(\w*))([\s.!()/]|$)/g,'$1<a target="_blank" href="http://search.twitter.com/search?q=%23$3">$2</a>$4');
  713.  
  714.                 // Markdown //
  715.                 tweet.text = Tweetbar.markDown.makeHtml(tweet.text);
  716.                 
  717.                 //icons
  718.                 link_dm = '<a class="re" href="#" onclick="setReplyDM(\''+ tweet.sender.screen_name + '\'); return false;"><img class="re" src="chrome://twitkitplus/skin/images/reply.png" alt="" /></a>';
  719.  
  720.                 link_reply_with_pic = '<a href="#" onclick="setReplyDM(\'' + tweet.sender.screen_name + '\');">'+ sender_image + '</a>';
  721.                 
  722.                 link_follow = '<a class="re" href="javascript: Tweetbar.follow_user(\'' + tweet.sender.screen_name + '\'); void 0;" onmouseover="$(\'nav-label\').innerHTML = \'follow\';" onmouseout="$(\'nav-label\').innerHTML = \' \';"><img class="re" src="chrome://twitkitplus/skin/images/follow.png" /></a>';
  723.  
  724.                 link_unfollow = '<a class="re" href="javascript: Tweetbar.unfollow_user(\'' + tweet.sender.screen_name + '\'); void 0;" onmouseover="$(\'nav-label\').innerHTML = \'unfollow\';" onmouseout="$(\'nav-label\').innerHTML = \' \';"><img class="re" src="chrome://twitkitplus/skin/images/unfollow.png" alt="" /></a>';
  725.  
  726.                 link_userinfo = '<a href="#" onclick="Tweetbar.activate_panel(\'me\',this,\'' + tweet.sender.screen_name + '\'); void 0;" onmouseover="$(\'nav-label\').innerHTML = Tweetbar._(\'tabs.me.title\');" onmouseout="$(\'nav-label\').innerHTML = \' \';"><img class="re" src="chrome://twitkitplus/skin/tabs/me.png" width=10 height=10 /></a>';
  727.  
  728.                 link_debug = '';
  729.                 //link_debug = '<a class="re" href="#" onclick = "var hohoge = \'' + escape(tweet.toSource().replace(/,/g, "\n").replace(/\\/g, "%")) + '\'; alert(unescape((unescape(hohoge))));" onmouseover="$(\'nav-label\').innerHTML = \'debug.info.decoded\';" onmouseout="$(\'nav-label\').innerHTML = \' \';"><img class="re" src="chrome://twitkitplus/skin/images/debug.png" alt="" /></a> <a class="re" href="#" onclick = "var hohoge = \'' + escape(tweet.toSource().replace(/,/g, "\n")) + '\'; alert(unescape((unescape(hohoge))));" onmouseover="$(\'nav-label\').innerHTML = \'debug.info\';" onmouseout="$(\'nav-label\').innerHTML = \' \';"><img class="re" src="chrome://twitkitplus/skin/images/debug.png" alt="" /></a>';
  730.                 link_icon = link_dm + ' ' + link_userinfo + ' ' + link_follow + ' ' + link_unfollow ;
  731.  
  732.                 return '<p class="pic">' + link_reply_with_pic +  link_debug + '</p>' +
  733.                        '<p class="what">' + tweet.text + '</p>' +
  734.                        '<p class="who">' + this.user_anchor_tag(tweet.sender) + date + '</p>' + 
  735.                        '<div class="source">' + link_icon + '</div>';
  736.  
  737.  
  738. //                return '<p class="pic"><a href="#" onclick="setReplyDM(\'' + tweet.sender.screen_name + '\');">'+ sender_image + '</a>' +
  739. //                       '<span class="re"><a class="re" href="#" onclick="setReplyDM(\''+ tweet.sender.screen_name + '\'); return false;"><img class="re" src="chrome://twitkitplus/skin/images/reply.png" alt="" /></a> ' + '</span></p>' +
  740. //                       '<p class="what">' + tweet.text + '</p>' +
  741. //                       '<p class="who">' + this.user_anchor_tag(tweet.sender) + date + '</p>';
  742.             }
  743.         },
  744.     /**
  745.      * Render a user (but don't print it).
  746.      * 
  747.      * @param {Object} user A user object returned by Tweetbar#create_user_object.
  748.      * @returns {String} Fully-rendered user HTML.
  749.      * @see Tweetbar#create_user_object
  750.      * @methodOf Tweetbar
  751.      * @since 1.0
  752.      */
  753.     render_user:
  754.         function (user) {
  755.             status = user.status.text;
  756.             if ( user.protected == true ) {
  757.                 status = '<em>' + this._('tabs.friends.protected') + '</em>';
  758.             } else {
  759.                 /*
  760.                  * Hashtags implementation - by Joschi
  761.                  */
  762.                 status = Tweetbar.expand_status(status);
  763.                 status = status.replace(/(#(\w*))/g,'<a target="_blank" href="http://search.twitter.com/search?q=%23$2">$1</a>');
  764.             }
  765.     
  766.             return '<p class="pic"><a href="#" onclick="setReply(\'' + user.screen_name + '\');"><img src="' + user.profile_image_url + '" width="24" height="24" alt="' + user.name + '" /></a>' +
  767.                    '<p class="what" style="font-size: 120%;">' + user.name + '</p>' +
  768.                    '<p class="who">' + status + '<br/>' +
  769.                    '<a target="_blank" href="' + Tweetbar.protocol + '://twitter.com/' + user.screen_name + '">' + user.screen_name + '</a></p>';
  770.         },
  771.     // List Updating //
  772.     /**
  773.      * Update the current list of tweets (print it).
  774.      * 
  775.      * @methodOf Tweetbar
  776.      * @since 1.0
  777.      */
  778.     add_current_list:
  779.         function (maxid) {
  780.             if ( ( this.currentList == 'public_timeline' ) || ( this.currentList == 'home_timeline' ) ) {
  781.                 var current_tweets = this.current_tweets();
  782.                 var tweet_ids = [];
  783.                 for ( var tid in current_tweets ){
  784.                     tweet_ids.push(tid);
  785.                 }
  786.                 var max_tweet_id = 0;
  787.                 tweet_ids = tweet_ids.sort().reverse();
  788.                 for ( var i=1; i < tweet_ids.length; i++ ) {
  789.                     var li = new Element('li');
  790.                     li.setHTML(this.render_tweet(current_tweets[tweet_ids[i]], li));
  791.                     if ( ( i % 2 ) == 0 )
  792.                         li.addClass('even');
  793.                     if ( Tweetbar.username && current_tweets[tweet_ids[i]].text.search('@' + Tweetbar.username) !== -1 )
  794.                         li.addClass('reply');
  795.                     li.injectInside($('tweets'));
  796.                     max_tweet_id = current_tweets[tweet_ids[i]].id;
  797.                 }
  798.                 var li = new Element('li');
  799.                 li.setHTML('<p class="what"><a href="javascript: Tweetbar.get_more_tweets(\'' + max_tweet_id + '\');"><img class="re" src="chrome://twitkitplus/skin/images/more.png" alt="" /> more 20 tweets</a></p>');
  800.                 li.injectInside($('tweets'));
  801.             } else if ( this.currentList == 'replies' ) {
  802.                 var current_tweets = this.current_tweets();
  803.                 var tweet_ids = [];
  804.                 for ( var tid in current_tweets ){
  805.                     tweet_ids.push(tid);
  806.                 }
  807.                 var max_tweet_id = 0;
  808.                 tweet_ids = tweet_ids.sort().reverse();
  809.                 for ( var i=1; i < tweet_ids.length; i++ ) {
  810.                     var li = new Element('li');
  811.                     li.setHTML(this.render_tweet(current_tweets[tweet_ids[i]], li));
  812.                     if ( ( i % 2 ) == 1 ){
  813.                         li.addClass('even');
  814.                     }
  815.                     li.injectInside($('tweets'));
  816.                     max_tweet_id = current_tweets[tweet_ids[i]].id;
  817.                 }
  818.                 var li = new Element('li');
  819.                 li.setHTML('<p class="what"><a href="javascript: Tweetbar.get_more_tweets(\'' + max_tweet_id + '\');"><img class="re" src="chrome://twitkitplus/skin/images/more.png" alt="" /> more 20 tweets</a></p>');
  820.                 li.injectInside($('tweets'));
  821.             } else if ( this.currentList == 'direct_messages' ) {
  822.                 var aj = new Ajax( Tweetbar.protocol + '://twitter.com/direct_messages.json?max_id=' + maxid, {
  823.                     headers: Tweetbar.http_headers(),
  824.                     method: 'get',
  825.                     postBody: {},
  826.                     onSuccess:
  827.                         function (raw_data) {
  828.                             var rsp = Json.evaluate(raw_data);
  829.                             var max_tweet_id = 0;
  830.                             for ( var i=1; i < rsp.length; i++ ) {
  831.                                 var li = new Element('li');
  832.                                 rsp[i].text = Tweetbar.expand_status(rsp[i].text);
  833.                                 li.setHTML(Tweetbar.render_direct_message(rsp[i]));
  834.                                 if ( ( i % 2 ) == 1 )
  835.                                     li.addClass('even');
  836.                                 li.injectInside('tweets');
  837.                                 max_tweet_id = rsp[i].id;
  838.                             }
  839.                             var li = new Element('li');
  840.                             li.setHTML('<p class="what"><a href="javascript: Tweetbar.add_current_list(\'' + max_tweet_id + '\');"><img class="re" src="chrome://twitkitplus/skin/images/more.png" alt="" /> more 20 tweets</a></p>');
  841.                             li.injectInside($('tweets'));
  842.                         }
  843.                 }).request();
  844.             }
  845.  
  846.         },
  847.     /**
  848.      * Update the current list of tweets (print it).
  849.      * 
  850.      * @methodOf Tweetbar
  851.      * @since 1.0
  852.      */
  853.     update_current_list:
  854.         function (screen_name) {
  855.             $('tweets').setHTML('');
  856.             if ( ( this.currentList == 'public_timeline' ) || ( this.currentList == 'home_timeline' ) ) {
  857.                 var current_tweets = this.current_tweets();
  858.                 var tweet_ids = [];
  859.                 for ( var tid in current_tweets ){
  860.                     tweet_ids.push(tid);
  861.                 }
  862.                 var max_tweet_id = 0;
  863.                 tweet_ids = tweet_ids.sort().reverse();
  864.                 for ( var i=0; i < tweet_ids.length; i++ ) {
  865.                     var li = new Element('li');
  866.                     li.setHTML(this.render_tweet(current_tweets[tweet_ids[i]], li));
  867.                     if ( ( i % 2 ) == 0 ){
  868.                         li.addClass('even');
  869.                     }
  870.                     if ( Tweetbar.username && current_tweets[tweet_ids[i]].text.search('@' + Tweetbar.username) !== -1 ){
  871.                         li.addClass('reply');
  872.                     }
  873.                     li.injectInside($('tweets'));
  874.                     max_tweet_id = current_tweets[tweet_ids[i]].id;
  875.                 }
  876.                 var li = new Element('li');
  877.                 li.setHTML('<p class="what"><a href="javascript: Tweetbar.get_more_tweets(\'' + max_tweet_id + '\');"><img class="re" src="chrome://twitkitplus/skin/images/more.png" alt="" /> more 20 tweets</a></p>');
  878.                 li.injectInside($('tweets'));
  879.                 
  880.             } else if ( this.currentList == 'friends' || this.currentList == 'followers' ) {
  881.                 ( this.currentList == 'friends' ) ? theurl = Tweetbar.protocol + '://twitter.com/statuses/friends/' + this.username + '.json?lite=true' : theurl = Tweetbar.protocol + '://twitter.com/statuses/followers.json?lite=true';
  882.                 var aj = new Ajax( theurl, {
  883.                     headers: Tweetbar.http_headers(),
  884.                     method: 'get',
  885.                     postBody: {},
  886.                     onSuccess:
  887.                         function (raw_data) {
  888.                             var rsp = Json.evaluate(raw_data);
  889.                             var i = 0;
  890.                             for ( var user in rsp ) {
  891.                                 if ( (rsp[user]['screen_name'] != undefined) && (rsp[user]['screen_name'] != 'forEach') ) {
  892.                                     var li = new Element('li');
  893.                                     li.setHTML(Tweetbar.render_user(rsp[user]));
  894.                                     if ( ( i % 2 ) == 0 )
  895.                                         li.addClass('even');
  896.                                     li.injectInside('tweets');
  897.                                     i++;
  898.                                 }
  899.                             }
  900.                         }
  901.                 }).request();
  902.             } else if ( this.currentList == 'replies' ) {
  903.                 var aj = new Ajax( Tweetbar.protocol + '://twitter.com/statuses/mentions.json', {
  904.                     headers: Tweetbar.http_headers(),
  905.                     method: 'get',
  906.                     postBody: {},
  907.                     onSuccess:
  908.                         function (raw_data) {
  909.                             var rsp = Json.evaluate(raw_data);
  910.                             var max_tweet_id = 0;
  911.                             for ( var i=0; i < rsp.length; i++ ) {
  912.                                 var li = new Element('li');
  913.                                 rsp[i].text = Tweetbar.expand_status(rsp[i].text);
  914.                                 li.setHTML(Tweetbar.render_tweet(rsp[i]));
  915.                                 if ( ( i % 2 ) == 0 ){
  916.                                     li.addClass('even');
  917.                                 }
  918.                                 li.injectInside('tweets');
  919.                                 max_tweet_id = rsp[i].id;
  920.                             }
  921.                             var li = new Element('li');
  922.                             li.setHTML('<p class="what"><a href="javascript: Tweetbar.get_more_tweets(\'' + max_tweet_id + '\');"><img class="re" src="chrome://twitkitplus/skin/images/more.png" alt="" /> more 20 tweets</a></p>');
  923.                             li.injectInside($('tweets'));
  924.                         }
  925.                 }).request();
  926.             } else if ( this.currentList == 'direct_messages' ) {
  927.                 var aj = new Ajax( Tweetbar.protocol + '://twitter.com/direct_messages.json', {
  928.                     headers: Tweetbar.http_headers(),
  929.                     method: 'get',
  930.                     postBody: {},
  931.                     onSuccess:
  932.                         function (raw_data) {
  933.                             var rsp = Json.evaluate(raw_data);
  934.                             var max_tweet_id = 0;
  935.                             for ( var i=0; i < rsp.length; i++ ) {
  936.                                 var li = new Element('li');
  937.                                 rsp[i].text = Tweetbar.expand_status(rsp[i].text);
  938.                                 li.setHTML(Tweetbar.render_direct_message(rsp[i]));
  939.                                 if ( ( i % 2 ) == 0 ){
  940.                                     li.addClass('even');
  941.                                 }
  942.                                 li.injectInside('tweets');
  943.                                 max_tweet_id = rsp[i].id;
  944.                             }
  945.                             var li = new Element('li');
  946.                             li.setHTML('<p class="what"><a href="javascript: Tweetbar.add_current_list(\'' + max_tweet_id + '\');"><img class="re" src="chrome://twitkitplus/skin/images/more.png" alt="" /> more 20 tweets</a></p>');
  947.                             li.injectInside($('tweets'));
  948.                         }
  949.                 }).request();
  950.             } else if ( this.currentList == 'me' ) {
  951.                 if(!screen_name){
  952.                     screen_name = this.username;
  953.                 }
  954.                 var temp_inner = '';
  955.  
  956.                 var aj = new Ajax( Tweetbar.protocol + '://twitter.com/users/show/' + screen_name + '.json', {
  957.                     headers: Tweetbar.http_headers(),
  958.                     method: 'get',
  959.                     postBody: {},
  960.                     onSuccess:
  961.                         function (raw_data) {
  962.                             var tweets = $('tweets');
  963.                             var user = Json.evaluate(raw_data);
  964.                             link_follow = '<a class="re" href="javascript: Tweetbar.follow_user(\'' + screen_name + '\'); void 0;" onmouseover="$(\'nav-label\').innerHTML = \'follow\';" onmouseout="$(\'nav-label\').innerHTML = \' \';"><img class="re" src="chrome://twitkitplus/skin/images/follow.png" /></a>';
  965.                             link_unfollow = '<a class="re" href="javascript: Tweetbar.unfollow_user(\'' + screen_name + '\'); void 0;" onmouseover="$(\'nav-label\').innerHTML = \'unfollow\';" onmouseout="$(\'nav-label\').innerHTML = \' \';"><img class="re" src="chrome://twitkitplus/skin/images/unfollow.png" alt="" /></a>';
  966.  
  967.                             var inner = '<div style="padding-bottom: 10px;">' +
  968.                                 '<img src="' + user.profile_image_url + '" alt="' + screen_name + '" style="float: right; width: 48px; height: 48px;" />' +
  969.                                 '<div style="font-size: 110%;"><a href="' + Tweetbar.protocol + '://twitter.com/' + screen_name + '" target="_blank">'+ screen_name +'</a> ' + link_follow + ' ' + link_unfollow +'</div>' +
  970.                                 '<div style="font-size: 0.8em;">' +
  971.                                 '<strong>' + Tweetbar._('tabs.me.location') + '</strong>: ' + user.location + '<br/>' +
  972.                                 '<strong>' + Tweetbar._('tabs.me.bio') + '</strong>: ' + Tweetbar.expand_status(user.description) + '<br/>' +
  973.                                 '<strong>' + Tweetbar._('tabs.me.friends') + '</strong>: ' + user.friends_count + '<br/>' +
  974.                                 '<strong>' + Tweetbar._('tabs.me.followers') + '</strong>: ' + user.followers_count + '<br/>' +
  975.                                 '<strong>' + Tweetbar._('tabs.me.favorites') + '</strong>: ' + user.favourites_count + '<br/>' +
  976.                                 '<strong>' + Tweetbar._('tabs.me.updates') + '</strong>: ' + user.statuses_count + '</div>' +
  977.                                 '</div>';
  978.                             tweets.setHTML(inner);
  979.                         }
  980.                 }).request();
  981.  
  982.                 var aj = new Ajax( Tweetbar.protocol + '://twitter.com/statuses/user_timeline.json?screen_name=' + screen_name , {
  983.                     headers: Tweetbar.http_headers(),
  984.                     method: 'get',
  985.                     postBody: {},
  986.                     onSuccess:
  987.                         function (raw_data) {
  988.                             var tweets = $('tweets');
  989.                             var rsp = Json.evaluate(raw_data);
  990.                             var max_tweet_id = 0;
  991.                             for ( var i=0; i < rsp.length; i++ ) {
  992.                                 var li = new Element('li');
  993.                                 rsp[i].text = Tweetbar.expand_status(rsp[i].text);
  994.                                 li.setHTML(Tweetbar.render_tweet(rsp[i]));
  995.                                 //temp_inner += '<li>' + Tweetbar.render_tweet(rsp[i]) + '</li>';
  996.                                 if ( ( i % 2 ) == 0 ){
  997.                                     li.addClass('even');
  998.                                 }
  999.                                 li.injectInside($('tweets'));
  1000.                                 max_tweet_id = rsp[i].id;
  1001.                             }
  1002.                         }
  1003.                 }).request();
  1004.  
  1005.             }
  1006.         },
  1007.     /**
  1008.      * Retrieve tweets from Twitter.
  1009.      * 
  1010.      * @methodOf Tweetbar
  1011.      * @since 1.0
  1012.      */
  1013.     get_tweets:
  1014.         function (screen_name) {
  1015.             var panel = Tweetbar.currentList;
  1016.             var url = Tweetbar.api_url_for_statuses(panel,'');
  1017.             if ( panel == 'direct_messages' ){
  1018.                 url = Tweetbar.api_url_for_nonstatuses(panel,'');
  1019.             }
  1020.             var aj = new Ajax( url, {
  1021.                 headers: Tweetbar.http_headers(),
  1022.                 method: 'get',
  1023.                 postBody: {},
  1024.                 onComplete:
  1025.                     function (raw_data) {
  1026.                         Tweetbar.hide_refresh_activity();
  1027.                         Tweetbar.set_updater();
  1028.                     },
  1029.                 onSuccess:
  1030.                     function (raw_data) {
  1031.                         Tweetbar.save_tweets(panel, raw_data);
  1032.                         Tweetbar.update_current_list(screen_name);
  1033.                     },
  1034.                 onFailure:
  1035.                     function (e) {
  1036.                         Tweetbar.hide_refresh_activity();
  1037.                         Tweetbar.set_updater();
  1038.                     },
  1039.                 onRequest:
  1040.                     function () {
  1041.                         Tweetbar.show_refresh_activity();
  1042.                         Tweetbar.clear_updater();
  1043.                     }
  1044.             }).request();
  1045.         },
  1046.     /**
  1047.      * Retrieve tweets from Twitter.
  1048.      * 
  1049.      * @methodOf Tweetbar
  1050.      * @since 1.0
  1051.      */
  1052.     get_more_tweets:
  1053.         function (maxid) {
  1054.             //alert(maxid);
  1055.             var panel = Tweetbar.currentList;
  1056.             var url = Tweetbar.api_url_for_statuses(panel,'?max_id=' + maxid);
  1057.             if ( panel == 'direct_messages' ){
  1058.                 url = Tweetbar.api_url_for_nonstatuses(panel,'?max_id=' + maxid);
  1059.             }
  1060.             var aj = new Ajax( url, {
  1061.                 headers: Tweetbar.http_headers(),
  1062.                 method: 'get',
  1063.                 postBody: {},
  1064.                 onComplete:
  1065.                     function (raw_data) {
  1066.                         Tweetbar.hide_refresh_activity();
  1067.                         Tweetbar.set_updater();
  1068.                     },
  1069.                 onSuccess:
  1070.                     function (raw_data) {
  1071.                         Tweetbar.save_tweets(panel, raw_data);
  1072.                         Tweetbar.add_current_list();
  1073.                     },
  1074.                 onFailure:
  1075.                     function (e) {
  1076.                         Tweetbar.hide_refresh_activity();
  1077.                         Tweetbar.set_updater();
  1078.                     },
  1079.                 onRequest:
  1080.                     function () {
  1081.                         Tweetbar.show_refresh_activity();
  1082.                         Tweetbar.clear_updater();
  1083.                     }
  1084.             }).request();
  1085.         },
  1086.     /**
  1087.      * Save the fresh tweets to the current panel's registry.
  1088.      * 
  1089.      * @param {String} panel The name of the current panel.
  1090.      * @param {Object} response_data Raw JSON response data from a Twitter API request.
  1091.      * @methodOf Tweetbar
  1092.      * @since 1.0
  1093.      */
  1094.     save_tweets:
  1095.         function (panel, response_data) {
  1096.             var new_tweets = Json.evaluate(response_data);
  1097.             this.tweets[panel] = {};
  1098.             for ( var i = 0; i < new_tweets.length; i++ ) {
  1099.                 if ( new_tweets[i].user ) {
  1100.                     var status = Tweetbar.create_status_object(new_tweets[i]);
  1101.                     if ( !this.tweets[panel][status.id] ) {
  1102.                         this.tweets[panel][status.id] = status;
  1103.                         this.tweets[panel][status.id].user = Tweetbar.create_user_object(new_tweets[i].user);
  1104.                     }
  1105.                 } else {
  1106.                     var user = Tweetbar.create_user_object(new_tweets[i]);
  1107.                     var status = Tweetbar.create_status_object(new_tweets[i].status);
  1108.                     var name_key = user.screen_name.toLowerCase();
  1109.                     if ( !this.tweets[panel][name_key] || ( this.tweets[panel][name_key].status.id != status.id ) ) {
  1110.                         this.tweets[panel][name_key] = status;
  1111.                         this.tweets[panel][name_key].user = user;
  1112.                     }
  1113.                 }
  1114.             }
  1115.         },
  1116.     
  1117.     // Refresh //
  1118.     /**
  1119.      * Show the refresher label and icon.
  1120.      * 
  1121.      * @methodOf Tweetbar
  1122.      * @since 1.0
  1123.      */
  1124.     show_refresh_activity:
  1125.         function () {
  1126.             $('refresh_activity').setStyle('display', 'block');
  1127.             $('refreshing').setStyle('display', 'inline');
  1128.         },
  1129.     /**
  1130.      * Hide the refresher label and icon.
  1131.      * 
  1132.      * @methodOf Tweetbar
  1133.      * @since 1.0
  1134.      */
  1135.     hide_refresh_activity:
  1136.         function () {
  1137.             $('refresh_activity').setStyle('display', 'none');
  1138.             $('refreshing').setStyle('display', 'none');
  1139.         },
  1140.     /**
  1141.      * Stop periodical updates.
  1142.      * 
  1143.      * @methodOf Tweetbar
  1144.      * @since 1.0
  1145.      */
  1146.     clear_updater:
  1147.         function () {
  1148.             if ( this.updater )
  1149.                 $clear(this.updater);
  1150.         },
  1151.     /**
  1152.      * Reset (or start for the first time) periodical updates.
  1153.      * 
  1154.      * @methodOf Tweetbar
  1155.      * @since 1.0
  1156.      */
  1157.     set_updater:
  1158.         function () {
  1159.             this.clear_updater();
  1160.             var interval = Tweetbar.prefService.getIntPref('refreshInterval');
  1161.             var up_int = parseInt(interval);
  1162.             this.updater = this.get_tweets.periodical(up_int);
  1163.         },
  1164.     /**
  1165.      * Refresh the current panel, regardless of the periodical updater. Used when user manually clicks 'refresh'.
  1166.      * 
  1167.      * @methodOf Tweetbar
  1168.      * @since 1.0
  1169.      */
  1170.     manual_refresh:
  1171.         function (screen_name) {
  1172.             this.clear_updater();
  1173.             this.get_tweets(screen_name);
  1174.             this.set_updater();
  1175.         },
  1176.     
  1177.     // Tweet Actions //    
  1178.  
  1179.     /**
  1180.      * Follow user.
  1181.      * 
  1182.      * @param {String} tweetid The ID of the tweet to add to favorites.
  1183.      * @methodOf Tweetbar
  1184.      * @since 1.0
  1185.      */
  1186.     follow_user:
  1187.         function (username) {
  1188.             var aj = new Ajax( Tweetbar.protocol + '://twitter.com/friendships/create/' + username + '.json', {
  1189.                 headers: Tweetbar.http_headers(),
  1190.                 postBody: {},
  1191.                 onSuccess:
  1192.                     function () {
  1193.                         alert('new follow Success:' + username);
  1194.                         //no action
  1195.                     },
  1196.                 onFailure:
  1197.                     function (e) {
  1198.                         alert(this._('errors.ajax') + e);
  1199.                     }
  1200.             }).request();
  1201.         },
  1202.     /**
  1203.      * unFollow user.
  1204.      * 
  1205.      * @param {String} tweetid The ID of the tweet to add to favorites.
  1206.      * @methodOf Tweetbar
  1207.      * @since 1.0
  1208.      */
  1209.     unfollow_user:
  1210.         function (username) {
  1211.             var aj = new Ajax( Tweetbar.protocol + '://twitter.com/friendships/destroy/' + username + '.json', {
  1212.                 headers: Tweetbar.http_headers(),
  1213.                 postBody: {},
  1214.                 onSuccess:
  1215.                     function () {
  1216.                         alert('unfollow Success:' + username);
  1217.                     },
  1218.                 onFailure:
  1219.                     function (e) {
  1220.                         alert(this._('errors.ajax') + e);
  1221.                     }
  1222.             }).request();
  1223.         },        
  1224.     /**
  1225.      * Add a tweet to the user's favorites.
  1226.      * 
  1227.      * @param {String} tweetid The ID of the tweet to add to favorites.
  1228.      * @methodOf Tweetbar
  1229.      * @since 1.0
  1230.      */
  1231.     fav_tweet:
  1232.         function (tweetid) {
  1233.             var aj = new Ajax( Tweetbar.protocol + '://twitter.com/favorites/create/' + tweetid + '.json', {
  1234.                 headers: Tweetbar.http_headers(),
  1235.                 postBody: {},
  1236.                 onSuccess:
  1237.                     function () {
  1238.                         var x = document.getElementById('fav-' + tweetid);
  1239.                         x.src = 'chrome://twitkitplus/skin/images/fav_remove.png';
  1240.                     },
  1241.                 onFailure:
  1242.                     function (e) {
  1243.                         alert(this._('errors.ajax') + e);
  1244.                     }
  1245.             }).request();
  1246.         },
  1247.     /**
  1248.      * Remove a tweet from the user's favorites.
  1249.      * 
  1250.      * @param {String} tweetid The ID of the tweet to remove from favorites.
  1251.      * @methodOf Tweetbar
  1252.      * @since 1.1
  1253.      */
  1254.     unfav_tweet:
  1255.         function (tweetid) {
  1256.             var aj = new Ajax( Tweetbar.protocol + '://twitter.com/favorites/destroy/' + tweetid + '.json', {
  1257.                 headers: Tweetbar.http_headers(),
  1258.                 postBody: {},
  1259.                 onSuccess:
  1260.                     function () {
  1261.                         var x = document.getElementById('fav-' + tweetid);
  1262.                         x.src = 'chrome://twitkitplus/skin/images/fav_add.png';
  1263.                     },
  1264.                 onFailure:
  1265.                     function (e) {
  1266.                         alert(this._('errors.ajax') + e);
  1267.                     }
  1268.             }).request();
  1269.         },
  1270.     /**
  1271.      * Delete one of the user's tweets.
  1272.      * 
  1273.      * @param {String} tweetid The ID of the tweet to delete. The user MUST own this tweet.
  1274.      * @methodOf Tweetbar
  1275.      * @since 1.0
  1276.      */
  1277.     delete_tweet:
  1278.         function (tweetid) {
  1279.             var aj = new Ajax( Tweetbar.protocol + '://twitter.com/statuses/destroy/' + tweetid + '.json', {
  1280.                 headers: Tweetbar.http_headers(),
  1281.                 postBody: {},
  1282.                 onSuccess:
  1283.                     function () {
  1284.                         delete Tweetbar.tweets[Tweetbar.currentList][tweetid];
  1285.                         var slider = new Fx.Slide(tweetid);
  1286.                         slider.toggle();
  1287.                     },
  1288.                 onFailure:
  1289.                     function (e) {
  1290.                         alert(this._('errors.ajax') + e);
  1291.                 }
  1292.             }).request();
  1293.         },
  1294.     /**
  1295.      * Umbrella function for updating the user's status -
  1296.      * does some authentication checking and then runs the
  1297.      * actual update function, Tweetbar#send_tweet.
  1298.      * 
  1299.      * @methodOf Tweetbar
  1300.      * @since 1.0
  1301.      */
  1302.     update_status:
  1303.         function (status,replyid, callback) {
  1304.             if ( this.isAuthenticated )
  1305.                 this.send_tweet(status,replyid, callback);
  1306.             else {
  1307.                 this.authenticate('update');
  1308.                 this.pendingUpdate = {callback: callback, status: status};
  1309.             }
  1310.         },
  1311.     /**
  1312.      * Send a status update to Twitter.
  1313.      * 
  1314.      * @param {String} status Status to send to Twitter
  1315.      * @param {Function} [callback=""] Function to run after the tweet is successfully sent
  1316.      * @methodOf Tweetbar
  1317.      * @since 1.0
  1318.      */
  1319.     send_tweet:
  1320.         function (status,replyid, callback) {
  1321.             var aj = new Ajax( Tweetbar.api_url_for_statuses('update'), {
  1322.                 headers: Tweetbar.http_headers(),
  1323.                 postBody: Object.toQueryString({status: status,in_reply_to_status_id: replyid,source: 'twitkit'}),
  1324.                 onComplete:
  1325.                     function () {
  1326.                         callback();
  1327.                     },
  1328.                 onSuccess:
  1329.                     function (raw_data) {
  1330.                         Tweetbar.save_tweets(this.currentList, raw_data);
  1331.                         if ( Tweetbar.currentList == 'home_timeline' )
  1332.                             setTimeout('Tweetbar.manual_refresh();', 1000);
  1333.                     },
  1334.                 onFailure:
  1335.                     function (e) {
  1336.                         alert(this._('errors.ajax') + e);
  1337.                     }
  1338.             }).request();
  1339.         },
  1340.  
  1341.     send_retweet:
  1342.         function (status,statusid, callback) {
  1343.             var aj = new Ajax( Tweetbar.api2_url_for_statuses(status + '/' + statusid ), {
  1344.                 headers: Tweetbar.http_headers(),
  1345. //                postBody: Object.toQueryString({status: status,in_reply_to_status_id: replyid,source: 'twitkit'}),
  1346.                 postBody: {},
  1347.                 onComplete:
  1348.                     function () {
  1349.                         callback();
  1350.                     },
  1351.                 onSuccess:
  1352.                     function (raw_data) {
  1353.                         $('nav-label').setHTML('finish retweet!');
  1354.                     },
  1355.                 onFailure:
  1356.                     function (e) {
  1357.                         alert(this._('errors.ajax') + e);
  1358.                     }
  1359.             }).request();
  1360.         },
  1361.     
  1362.     // Panel Functions //
  1363.     /**
  1364.      * Switch to a new panel.
  1365.      * 
  1366.      * @param {String} name The name of the panel to switch to.
  1367.      * @param {Object} [caller=""] A DOM object from where the function was called.
  1368.      * @methodOf Tweetbar
  1369.      * @since 1.0
  1370.      */
  1371.     activate_panel:
  1372.         function (name, caller,screen_name) {
  1373.             if ( name == '' ){
  1374.                 name = 'public_timeline';
  1375.             }
  1376.             if ( !this.authorization_required_for(name) || this.isAuthenticated ) {
  1377.                 this.currentList = name;
  1378.                 this.update_current_list(screen_name);
  1379.                 this.clear_current_tweets();
  1380.                 
  1381.                 $('tab_for_public_timeline').removeClass('active');
  1382.                 $('tab_for_home_timeline').removeClass('active');
  1383.                 $('tab_for_friends').removeClass('active');
  1384.                 $('tab_for_followers').removeClass('active');
  1385.                 $('tab_for_replies').removeClass('active');
  1386.                 $('tab_for_direct_messages').removeClass('active');
  1387.                 $('tab_for_me').removeClass('active');
  1388.                 
  1389.                 $('tab_for_'+ name).addClass('active');
  1390.                 
  1391.                 if ( caller )
  1392.                     caller.blur();
  1393.                 
  1394.                 Tweetbar.prefService.setCharPref('active_panel', name);
  1395.                 
  1396.                 this.clear_updater();
  1397.                 this.get_tweets(screen_name);
  1398.                 this.set_updater();
  1399.             } else {
  1400.                 alert(this._('misc.needAuth'));
  1401.                 this.authenticate(action);
  1402.             }
  1403.         },
  1404.     
  1405.     // Styling //
  1406.     /**
  1407.      * Adjust the list of tweets to fit Firefox's current window size.
  1408.      * 
  1409.      * @methodOf Tweetbar
  1410.      * @since 1.0
  1411.      */
  1412.     setListSize:
  1413.         function () {
  1414.             var h = Window.getHeight() -
  1415.                     ( $('topper').getSize()['size']['y'] +
  1416.                       $('navigation').getSize()['size']['y'] +
  1417.                       $('refresher').getSize()['size']['y']
  1418.                     );
  1419.             h -= 20;
  1420.             $('lists').setStyle('overflow', 'auto');
  1421.             $('lists').setStyle('height', h+'px');
  1422.             var w = Window.getWidth() + 15;
  1423.             $('tweets').setStyle('max-width', w+'px');
  1424.         },
  1425.     
  1426.     // Docking //
  1427.     /**
  1428.      * Undock TwitKit+.
  1429.      * 
  1430.      * @methodOf Tweetbar
  1431.      * @since 1.1
  1432.      */
  1433.     undock:
  1434.         function () {
  1435.             window.open('chrome://twitkitplus/content/twitkitplus.html?undocked', 'TwitKit+', 'width=300,resizable=yes,scrollbars=no,toolbar=no,location=no,directories=no,status=no,menubar=no,copyhistory=no');
  1436.             Tweetbar.DOMWindow.toggleSidebar('viewTweetbar');
  1437.         },
  1438.     
  1439.     // Authorization //
  1440.     /**
  1441.      * Toggle the display of the login window.
  1442.      * 
  1443.      * @methodOf Tweetbar
  1444.      * @since 1.0
  1445.      */
  1446.     toggle_login:
  1447.         function () {
  1448.             this.loginSlider.toggle();
  1449.         },
  1450.     /**
  1451.      * Close the login window.
  1452.      * 
  1453.      * @param {Object} [obj=""] A DOM object from where the function was called.
  1454.      * @methodOf Tweetbar
  1455.      * @since 1.0
  1456.      */
  1457.     close_login:
  1458.         function (obj) {
  1459.             this.loginSlider.slideOut();
  1460.             
  1461.             $('whoami').setHTML('<a href="#" class="signin" onclick="Tweetbar.open_login(this); return false;">' + this._('login.signIn') + '</a>');
  1462.             if ( obj )
  1463.                 obj.blur();
  1464.             
  1465.             var x = document.getElementById('username');
  1466.             x.value = '';
  1467.             
  1468.             x = document.getElementById('password');
  1469.             x.value = '';
  1470.         },
  1471.     /**
  1472.      * Open the login window.
  1473.      * 
  1474.      * @param {Object} [obj=""] A DOM object from where the function was called.
  1475.      * @methodOf Tweetbar
  1476.      * @since 1.0
  1477.      */
  1478.     open_login:
  1479.         function (obj) {
  1480.             this.loginSlider.slideIn();
  1481.             
  1482.             $('whoami').setHTML('<a href="#" class="signin" onclick="Tweetbar.close_login(this); return false;">' + this._('login.close') + '</a>');
  1483.             if ( obj )
  1484.                 obj.blur();
  1485.  
  1486.             $('username').focus();
  1487.         },
  1488.     /**
  1489.      * Check if authorization is required to make a certain
  1490.      * API request.
  1491.      * 
  1492.      * @param {String} resource The name of the API request.
  1493.      * @return {Boolean}
  1494.      * @methodOf Tweetbar
  1495.      * @since 1.0
  1496.      */
  1497.     authorization_required_for:
  1498.         function (resource) {
  1499.             if ( resource == 'public_timeline' )
  1500.                 return false;
  1501.             return true;
  1502.         },
  1503.     /**
  1504.      * Have the user log in, and then perform an action.
  1505.      * 
  1506.      * @param {String} action An action (API request) to perform.
  1507.      * @methodOf Tweetbar
  1508.      * @since 1.0
  1509.      */
  1510.     authenticate:
  1511.         function (action) {
  1512.             this.open_login();
  1513.             this.pendingAction = action;
  1514.         },
  1515.     /**
  1516.      * Sign out of the current Twitter account.
  1517.      * 
  1518.      * @methodOf Tweetbar
  1519.      * @since 1.0
  1520.      */
  1521.     sign_out:
  1522.         function () {
  1523.             var aj = new Ajax( Tweetbar.protocol + '://twitter.com/account/end_session.json', {
  1524.                 headers: Tweetbar.http_headers(),
  1525.                 postBody: {},
  1526.                 onSuccess:
  1527.                     function () {
  1528.                         this.username = null;
  1529.                         this.password = null;
  1530.                         Tweetbar.prefService.setCharPref('username', '');
  1531.                         Tweetbar.prefService.setCharPref('password', '');
  1532.                         this.isAuthenticated = false;
  1533.                         Tweetbar.clear_http_headers();
  1534.                         Tweetbar.clear_cookies();
  1535.                         
  1536.                         $('whoami').setHTML('<a href="#" class="signin" onclick="Tweetbar.open_login(this); return false;">' + Tweetbar._('login.signIn') + '</a>');
  1537.                         $('whoami').setStyle('backgroundColor', '#75b7ba');
  1538.                         $('loginwrap').setStyle('display', 'block');
  1539.                         Tweetbar.loginSlider.hide();
  1540.                         if ( Tweetbar.authorization_required_for(this.currentList) )
  1541.                             Tweetbar.activate_panel('public_timeline');
  1542.                     },
  1543.                 onFailure:
  1544.                     function () {
  1545.                         alert(Tweetbar._('errors.signOut'));
  1546.                     },
  1547.             }).request();
  1548.         },
  1549.     /**
  1550.      * Sign in to a Twitter account.
  1551.      * 
  1552.      * @param {String} un Twitter username
  1553.      * @param {String} pw Twitter password
  1554.      * @param {Function} [callback=""] A function to call once the action has completed successfully.
  1555.      * @methodOf Tweetbar
  1556.      * @since 1.0
  1557.      */
  1558.     sign_in:
  1559.         function (un, pw, callback) {
  1560.             this.username = un;
  1561.             this.password = pw;
  1562.             this.clear_http_headers();
  1563.             
  1564.             var aj = new Ajax( Tweetbar.protocol + '://twitter.com/account/verify_credentials', {
  1565.                 headers: this.http_headers(),
  1566.                 method: 'get',
  1567.                 postBody: {},
  1568.                 onComplete:
  1569.                     function (raw_data) {
  1570.                         if ( this.transport.status == 200 ) {
  1571.                             Tweetbar.isAuthenticated = true;
  1572.                             Tweetbar.prefService.setCharPref('username', Tweetbar.username);
  1573.                             Tweetbar.prefService.setCharPref('password', Tweetbar.password);
  1574.                             Tweetbar.close_login();
  1575.                             if ( Tweetbar.pendingAction ) {
  1576.                                 if ( Tweetbar.pendingAction == 'update' ) {
  1577.                                     Tweetbar.send_tweet(Tweetbar.pendingUpdate['status'],Tweetbar.pendingUpdate['replyid'], Tweetbar.pendingUpdate['callback']);
  1578.                                     Tweetbar.pendingAction = null;
  1579.                                     Tweetbar.pendingUpdate = null;
  1580.                                 } else {
  1581.                                     Tweetbar.activate_panel(Tweetbar.pendingAction);
  1582.                                     Tweetbar.pendingAction = null;
  1583.                                 }
  1584.                             }
  1585.                             Tweetbar.set_username_on_page();
  1586.                             } else
  1587.                                 alert(this._('errors.signOut'));
  1588.                             if ( callback ) {
  1589.                                 try { callback(); } catch(e) { };
  1590.                         }
  1591.                     },
  1592.             }).request();
  1593.         },
  1594.     /**
  1595.      * Show the current user's name and a sign-out button
  1596.      * after signing in.
  1597.      * 
  1598.      * @methodOf Tweetbar
  1599.      * @since 1.0
  1600.      */
  1601.     set_username_on_page:
  1602.         function () {
  1603.             $('whoami').setStyle('backgroundColor', 'transparent');
  1604.             $('whoami').setHTML('<p><a href="' + Tweetbar.protocol + '://twitter.com/' + Tweetbar.username + '" target="_blank">'+Tweetbar.username+'</a> [<a href="#" onclick="Tweetbar.sign_out(); return false;" alt="sign out" title="sign out">' + this._('login.signOut') + '</a>]</p>');
  1605.             $('loginwrap').setStyle('display', 'none');
  1606.         },
  1607.     
  1608. };
  1609.  
  1610. window.onload = function () {
  1611.     Tweetbar.run();
  1612. };
  1613.  
  1614. window.onresize = function () {
  1615.     Tweetbar.setListSize();
  1616. };
  1617.